package jmine.tec.utils.collection.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import jmine.tec.utils.collection.MultiMap;

/**
 * Implementa algumas funcoes basicas do {@link MultiMap}
 * 
 * @author takeshi
 * @param <K> o tipo da chave
 * @param <V> o tipo do valor
 */
public abstract class AbstractMultiMap<K, V> implements MultiMap<K, V> {

    /**
     * {@inheritDoc}
     */
    public void addAll(Map<? extends K, ? extends V> map) {
        Collection<? extends Entry<? extends K, ? extends V>> entrySet = map.entrySet();
        for (Entry<? extends K, ? extends V> entry : entrySet) {
            add(entry.getKey(), entry.getValue());
        }
    }

    /**
     * {@inheritDoc}
     */
    public int size() {
        int sum = 0;
        Iterator<Collection<V>> iterator = valuesIterator();
        while (iterator.hasNext()) {
            sum += iterator.next().size();
        }
        return sum;
    }

    /**
     * {@inheritDoc}
     */
    public void addAll(K key, Collection<? extends V> values) {
        for (V v : values) {
            add(key, v);
        }
    }

    /**
     * {@inheritDoc}
     */
    public void addAll(MultiMap<? extends K, ? extends V> map) {
        Collection<? extends Entry<? extends K, ? extends Collection<? extends V>>> col = map.entries();
        for (Entry<? extends K, ? extends Collection<? extends V>> entry : col) {
            addAll(entry.getKey(), entry.getValue());
        }
    }

    /**
     * {@inheritDoc}
     */
    public Set<? extends K> keySet() {
        return toPlainMap().keySet();
    }

    /**
     * {@inheritDoc}
     */
    public boolean containsKey(K key) {
        return toPlainMap().containsKey(key);
    }

    /**
     * {@inheritDoc}
     */
    public boolean containsValue(K key, V value) {
        Collection<? extends V> collection = get(key);
        return collection != null && collection.contains(value);
    }

    /**
     * {@inheritDoc}
     */
    public boolean containsValue(V value) {
        return values().contains(value);

    }

    /**
     * {@inheritDoc}
     */
    public Collection<? extends V> values() {
        Collection<V> accumulator = new ArrayList<V>();
        Iterator<Collection<V>> it = valuesIterator();
        while (it.hasNext()) {
            accumulator.addAll(it.next());
        }
        return accumulator;
    }

    /**
     * {@inheritDoc}
     */
    public void clear() {
        for (K key : keySet()) {
            removeAll(key);
        }
    }

    /**
     * {@inheritDoc}
     */
    public Collection<Entry<K, Collection<V>>> entries() {
        return toPlainMap().entrySet();
    }

    /**
     * {@inheritDoc}
     */
    public Iterator<Collection<V>> valuesIterator() {
        return toPlainMap().values().iterator();
    }

    /**
     * {@inheritDoc}
     */
    public boolean isEmpty() {
        return size() == 0;
    }

}
